@@ -0,0 +1,2 @@ |
||
| 1 |
+https://github.com/cantino/heroku-selectable-procfile.git |
|
| 2 |
+https://github.com/heroku/heroku-buildpack-ruby.git |
@@ -74,12 +74,9 @@ gem 'hipchat', '~> 1.2.0' |
||
| 74 | 74 |
gem 'xmpp4r', '~> 0.5.6' |
| 75 | 75 |
gem 'feed-normalizer' |
| 76 | 76 |
gem 'slack-notifier', '~> 0.5.0' |
| 77 |
- |
|
| 78 | 77 |
gem 'therubyracer', '~> 0.12.1' |
| 79 |
- |
|
| 80 | 78 |
gem 'mqtt' |
| 81 | 79 |
|
| 82 |
- |
|
| 83 | 80 |
group :development do |
| 84 | 81 |
gem 'binding_of_caller' |
| 85 | 82 |
gem 'better_errors' |
@@ -103,3 +100,17 @@ group :production do |
||
| 103 | 100 |
gem 'dotenv-deployment' |
| 104 | 101 |
gem 'rack' |
| 105 | 102 |
end |
| 103 |
+ |
|
| 104 |
+# This hack needs some explanation. When on Heroku, use the pg, unicorn, and rails12factor gems. |
|
| 105 |
+# When not on Heroku, we still want our Gemfile.lock to include these gems, so we scope them to |
|
| 106 |
+# an unsupported platform. |
|
| 107 |
+if ENV['ON_HEROKU'] || ENV['HEROKU_POSTGRESQL_ROSE_URL'] || File.read(File.join(File.dirname(__FILE__), 'Procfile')) =~ /intended for Heroku/ |
|
| 108 |
+ gem 'pg' |
|
| 109 |
+ gem 'unicorn' |
|
| 110 |
+ gem 'rails_12factor' |
|
| 111 |
+else |
|
| 112 |
+ gem 'pg', platform: :ruby_18 |
|
| 113 |
+ gem 'unicorn', platform: :ruby_18 |
|
| 114 |
+ gem 'rails_12factor', platform: :ruby_18 |
|
| 115 |
+end |
|
| 116 |
+ |
@@ -165,6 +165,7 @@ GEM |
||
| 165 | 165 |
kaminari (0.16.1) |
| 166 | 166 |
actionpack (>= 3.0.0) |
| 167 | 167 |
activesupport (>= 3.0.0) |
| 168 |
+ kgio (2.9.2) |
|
| 168 | 169 |
kramdown (1.3.3) |
| 169 | 170 |
launchy (2.4.2) |
| 170 | 171 |
addressable (~> 2.3) |
@@ -196,6 +197,7 @@ GEM |
||
| 196 | 197 |
multi_xml (~> 0.5) |
| 197 | 198 |
rack (~> 1.2) |
| 198 | 199 |
orm_adapter (0.5.0) |
| 200 |
+ pg (0.17.1) |
|
| 199 | 201 |
polyglot (0.3.5) |
| 200 | 202 |
protected_attributes (1.0.8) |
| 201 | 203 |
activemodel (>= 4.0.1, < 5.0) |
@@ -218,11 +220,17 @@ GEM |
||
| 218 | 220 |
bundler (>= 1.3.0, < 2.0) |
| 219 | 221 |
railties (= 4.1.4) |
| 220 | 222 |
sprockets-rails (~> 2.0) |
| 223 |
+ rails_12factor (0.0.2) |
|
| 224 |
+ rails_serve_static_assets |
|
| 225 |
+ rails_stdout_logging |
|
| 226 |
+ rails_serve_static_assets (0.0.2) |
|
| 227 |
+ rails_stdout_logging (0.0.3) |
|
| 221 | 228 |
railties (4.1.4) |
| 222 | 229 |
actionpack (= 4.1.4) |
| 223 | 230 |
activesupport (= 4.1.4) |
| 224 | 231 |
rake (>= 0.8.7) |
| 225 | 232 |
thor (>= 0.18.1, < 2.0) |
| 233 |
+ raindrops (0.13.0) |
|
| 226 | 234 |
rake (10.3.2) |
| 227 | 235 |
ref (1.0.5) |
| 228 | 236 |
rest-client (1.6.7) |
@@ -322,6 +330,10 @@ GEM |
||
| 322 | 330 |
uglifier (2.5.1) |
| 323 | 331 |
execjs (>= 0.3.0) |
| 324 | 332 |
json (>= 1.8.0) |
| 333 |
+ unicorn (4.8.3) |
|
| 334 |
+ kgio (~> 2.6) |
|
| 335 |
+ rack |
|
| 336 |
+ raindrops (~> 0.7) |
|
| 325 | 337 |
uuid (2.3.7) |
| 326 | 338 |
macaddr (~> 1.0) |
| 327 | 339 |
uuidtools (2.1.4) |
@@ -380,11 +392,13 @@ DEPENDENCIES |
||
| 380 | 392 |
mqtt |
| 381 | 393 |
mysql2 (~> 0.3.16) |
| 382 | 394 |
nokogiri (~> 1.6.1) |
| 395 |
+ pg |
|
| 383 | 396 |
protected_attributes (~> 1.0.8) |
| 384 | 397 |
pry |
| 385 | 398 |
quiet_assets |
| 386 | 399 |
rack |
| 387 | 400 |
rails (= 4.1.4) |
| 401 |
+ rails_12factor |
|
| 388 | 402 |
rr |
| 389 | 403 |
rspec (~> 2.14) |
| 390 | 404 |
rspec-rails (~> 2.14) |
@@ -401,6 +415,7 @@ DEPENDENCIES |
||
| 401 | 415 |
typhoeus (~> 0.6.3) |
| 402 | 416 |
tzinfo-data |
| 403 | 417 |
uglifier (>= 1.3.0) |
| 418 |
+ unicorn |
|
| 404 | 419 |
vcr |
| 405 | 420 |
webmock (~> 1.17.4) |
| 406 | 421 |
weibo_2 (~> 0.1.4) |
@@ -6,8 +6,8 @@ jobs: bundle exec rails runner bin/threaded.rb |
||
| 6 | 6 |
# web: bundle exec unicorn -c config/unicorn/production.rb |
| 7 | 7 |
# jobs: bundle exec rails runner bin/threaded.rb |
| 8 | 8 |
|
| 9 |
-# Old version with seperate processes (use this if you have issues with the threaded version) |
|
| 10 |
-#web: bundle exec rails server |
|
| 11 |
-#schedule: bundle exec rails runner bin/schedule.rb |
|
| 12 |
-#twitter: bundle exec rails runner bin/twitter_stream.rb |
|
| 13 |
-#dj: bundle exec script/delayed_job run |
|
| 9 |
+# Old version with separate processes (use this if you have issues with the threaded version) |
|
| 10 |
+# web: bundle exec rails server |
|
| 11 |
+# schedule: bundle exec rails runner bin/schedule.rb |
|
| 12 |
+# twitter: bundle exec rails runner bin/twitter_stream.rb |
|
| 13 |
+# dj: bundle exec script/delayed_job run |
@@ -38,7 +38,7 @@ module Agents |
||
| 38 | 38 |
'expected_receive_period_in_days' => "2", |
| 39 | 39 |
'group_by_path' => "filter", |
| 40 | 40 |
'value_path' => "count", |
| 41 |
- 'message' => "A peak was found" |
|
| 41 |
+ 'message' => "A peak of {{count}} was found in {{filter}}"
|
|
| 42 | 42 |
} |
| 43 | 43 |
end |
| 44 | 44 |
|
@@ -0,0 +1,160 @@ |
||
| 1 |
+#!/usr/bin/env ruby |
|
| 2 |
+require 'open3' |
|
| 3 |
+require 'io/console' |
|
| 4 |
+ |
|
| 5 |
+unless `which heroku` =~ /heroku/ |
|
| 6 |
+ puts "It looks like the heroku command line tool hasn't been installed yet. Please install" |
|
| 7 |
+ puts "the Heroku Toolbelt from https://toolbelt.heroku.com, run 'heroku auth:login', and then" |
|
| 8 |
+ puts "run this script again." |
|
| 9 |
+ exit 1 |
|
| 10 |
+end |
|
| 11 |
+ |
|
| 12 |
+def capture(cmd, opts = {})
|
|
| 13 |
+ o, s = Open3.capture2e(cmd, opts) |
|
| 14 |
+ o.strip |
|
| 15 |
+end |
|
| 16 |
+ |
|
| 17 |
+def ask(question, opts = {})
|
|
| 18 |
+ print question + " " |
|
| 19 |
+ STDOUT.flush |
|
| 20 |
+ (opts[:noecho] ? STDIN.noecho(&:gets) : gets).strip |
|
| 21 |
+end |
|
| 22 |
+ |
|
| 23 |
+def nag(question, opts = {})
|
|
| 24 |
+ answer = '' |
|
| 25 |
+ while answer.length == 0 |
|
| 26 |
+ answer = ask(question, opts) |
|
| 27 |
+ end |
|
| 28 |
+ answer |
|
| 29 |
+end |
|
| 30 |
+ |
|
| 31 |
+def yes?(question) |
|
| 32 |
+ ask(question + " (y/n)") =~ /^y/i |
|
| 33 |
+end |
|
| 34 |
+ |
|
| 35 |
+def grab_heroku_config! |
|
| 36 |
+ config_data = capture("heroku config -s")
|
|
| 37 |
+ $config = {}
|
|
| 38 |
+ if config_data !~ /has no config vars/ |
|
| 39 |
+ config_data.split("\n").map do |line|
|
|
| 40 |
+ next if line =~ /^\s*(#|$)/ # skip comments and empty lines |
|
| 41 |
+ first_equal_sign = line.index('=')
|
|
| 42 |
+ $config[line.slice(0, first_equal_sign)] = line.slice(first_equal_sign + 1, line.length) |
|
| 43 |
+ end |
|
| 44 |
+ end |
|
| 45 |
+end |
|
| 46 |
+ |
|
| 47 |
+def set_value(key, value, options = {})
|
|
| 48 |
+ if $config[key].nil? || $config[key] == '' || ($config[key] != value && options[:force] != false) |
|
| 49 |
+ puts "Setting #{key} to #{value}" unless options[:silent]
|
|
| 50 |
+ puts capture("heroku config:set #{key}=#{value}")
|
|
| 51 |
+ end |
|
| 52 |
+end |
|
| 53 |
+ |
|
| 54 |
+unless File.exists?(File.expand_path("~/.netrc")) && File.read(File.expand_path("~/.netrc")) =~ /heroku/
|
|
| 55 |
+ puts "It looks like you need to log in to Heroku. Please run 'heroku auth:login' before continuing." |
|
| 56 |
+ exit 1 |
|
| 57 |
+end |
|
| 58 |
+ |
|
| 59 |
+puts "Welcome #{`heroku auth:whoami`.strip}! It looks like you're logged into Heroku."
|
|
| 60 |
+puts |
|
| 61 |
+ |
|
| 62 |
+info = capture("heroku info")
|
|
| 63 |
+if info =~ /No app specified/i |
|
| 64 |
+ puts "It looks like you don't have a Heroku app set up yet for this repo." |
|
| 65 |
+ puts "You can either exit now and run 'heroku create', or I can do it for you." |
|
| 66 |
+ if yes?("Would you like me to create a Heroku app for you now in this repo?")
|
|
| 67 |
+ puts `heroku create` |
|
| 68 |
+ info = capture("heroku info")
|
|
| 69 |
+ else |
|
| 70 |
+ puts "Okay, exiting so you can do it." |
|
| 71 |
+ exit 0 |
|
| 72 |
+ end |
|
| 73 |
+end |
|
| 74 |
+ |
|
| 75 |
+app_name = info.scan(/http:\/\/([\w\d-]+)\.herokuapp\.com/).flatten.first |
|
| 76 |
+ |
|
| 77 |
+unless yes?("Your Heroku app name is #{app_name}. Is this correct?")
|
|
| 78 |
+ puts "Well, then I'm not sure what to do here, sorry." |
|
| 79 |
+ exit 1 |
|
| 80 |
+end |
|
| 81 |
+ |
|
| 82 |
+grab_heroku_config! |
|
| 83 |
+ |
|
| 84 |
+if $config.length > 0 |
|
| 85 |
+ puts |
|
| 86 |
+ puts "Your current Heroku config:" |
|
| 87 |
+ $config.each do |key, value| |
|
| 88 |
+ puts ' ' + key + ' ' * (25 - [key.length, 25].min) + '= ' + value |
|
| 89 |
+ end |
|
| 90 |
+end |
|
| 91 |
+ |
|
| 92 |
+unless $config['APP_SECRET_TOKEN'] |
|
| 93 |
+ puts "Setting up APP_SECRET_TOKEN..." |
|
| 94 |
+ puts capture("heroku config:set APP_SECRET_TOKEN=`rake secret`")
|
|
| 95 |
+end |
|
| 96 |
+ |
|
| 97 |
+set_value 'BUILDPACK_URL', "https://github.com/ddollar/heroku-buildpack-multi.git" |
|
| 98 |
+set_value 'PROCFILE_PATH', "deployment/heroku/Procfile.heroku", force: false |
|
| 99 |
+set_value 'ON_HEROKU', "true" |
|
| 100 |
+set_value 'FORCE_SSL', "true" |
|
| 101 |
+set_value 'DOMAIN', "#{app_name}.herokuapp.com", force: false
|
|
| 102 |
+ |
|
| 103 |
+unless $config['INVITATION_CODE'] |
|
| 104 |
+ puts "You need to set an invitation code for your Huginn instance. If you plan to share this instance, you will" |
|
| 105 |
+ puts "tell this code to anyone who you'd like to invite. If you won't share it, then just set this to something" |
|
| 106 |
+ puts "that people will not guess." |
|
| 107 |
+ |
|
| 108 |
+ invitation_code = nag("What code would you like to use?")
|
|
| 109 |
+ set_value 'INVITATION_CODE', invitation_code |
|
| 110 |
+end |
|
| 111 |
+ |
|
| 112 |
+unless $config['SMTP_DOMAIN'] && $config['SMTP_USER_NAME'] && $config['SMTP_PASSWORD'] && $config['SMTP_SERVER'] && $config['EMAIL_FROM_ADDRESS'] |
|
| 113 |
+ puts "Okay, let's setup outgoing email settings. The simplest solution is to use the free sendgrid Heroku addon." |
|
| 114 |
+ puts "If you'd like to use your own server, or your Gmail account, please see .env.example and set" |
|
| 115 |
+ puts "SMTP_DOMAIN, SMTP_USER_NAME, SMTP_PASSWORD, and SMTP_SERVER with 'heroku config:set'." |
|
| 116 |
+ if yes?("Should I enable the free sendgrid addon?")
|
|
| 117 |
+ puts capture("heroku addons:add sendgrid")
|
|
| 118 |
+ |
|
| 119 |
+ set_value 'SMTP_SERVER', "smtp.sendgrid.net", silent: true |
|
| 120 |
+ set_value 'SMTP_DOMAIN', "heroku.com", silent: true |
|
| 121 |
+ |
|
| 122 |
+ grab_heroku_config! |
|
| 123 |
+ set_value 'SMTP_USER_NAME', $config['SENDGRID_USERNAME'], silent: true |
|
| 124 |
+ set_value 'SMTP_PASSWORD', $config['SENDGRID_PASSWORD'], silent: true |
|
| 125 |
+ else |
|
| 126 |
+ puts "Okay, you'll need to set SMTP_DOMAIN, SMTP_USER_NAME, SMTP_PASSWORD, and SMTP_SERVER with 'heroku config:set' manually." |
|
| 127 |
+ end |
|
| 128 |
+ |
|
| 129 |
+ unless $config['EMAIL_FROM_ADDRESS'] |
|
| 130 |
+ email = nag("What email address would you like email to appear to be sent from?")
|
|
| 131 |
+ set_value 'EMAIL_FROM_ADDRESS', email |
|
| 132 |
+ end |
|
| 133 |
+end |
|
| 134 |
+ |
|
| 135 |
+branch = capture("git rev-parse --abbrev-ref HEAD")
|
|
| 136 |
+if yes?("Should I push your current branch (#{branch}) to heroku?")
|
|
| 137 |
+ puts "This may take a moment..." |
|
| 138 |
+ puts capture("git push heroku #{branch}:master -f")
|
|
| 139 |
+ |
|
| 140 |
+ puts "Running database migrations..." |
|
| 141 |
+ puts capture("heroku run rake db:migrate")
|
|
| 142 |
+ |
|
| 143 |
+ puts |
|
| 144 |
+ puts |
|
| 145 |
+ puts "I can make an admin user on your new Huginn instance and setup some example Agents." |
|
| 146 |
+ if yes?("Should I create a new admin user and some example Agents?")
|
|
| 147 |
+ seed_email = nag "Okay, what is your email address?" |
|
| 148 |
+ seed_username = nag "And what username would you like to login as?" |
|
| 149 |
+ seed_password = nag "Finally, what password would you like to use?", noecho: true |
|
| 150 |
+ puts "\nJust a moment..." |
|
| 151 |
+ |
|
| 152 |
+ capture("heroku run rake db:seed SEED_EMAIL=#{seed_email} SEED_USERNAME=#{seed_username} SEED_PASSWORD=#{seed_password}")
|
|
| 153 |
+ puts |
|
| 154 |
+ puts |
|
| 155 |
+ puts "Okay, you should be all set! Visit https://#{app_name}.herokuapp.com and login as '#{seed_username}' with your password."
|
|
| 156 |
+ end |
|
| 157 |
+end |
|
| 158 |
+ |
|
| 159 |
+puts |
|
| 160 |
+puts "Done!" |
@@ -5,5 +5,5 @@ Delayed::Worker.read_ahead = 5 |
||
| 5 | 5 |
Delayed::Worker.default_priority = 10 |
| 6 | 6 |
Delayed::Worker.delay_jobs = !Rails.env.test? |
| 7 | 7 |
|
| 8 |
-Delayed::Worker.logger = Logger.new(Rails.root.join('log', 'delayed_job.log'))
|
|
| 9 |
-Delayed::Worker.logger.level = Logger::DEBUG |
|
| 8 |
+# Delayed::Worker.logger = Logger.new(Rails.root.join('log', 'delayed_job.log'))
|
|
| 9 |
+# Delayed::Worker.logger.level = Logger::DEBUG |
@@ -1,10 +1,10 @@ |
||
| 1 | 1 |
# This file should contain all the record creation needed to seed the database with its default values. |
| 2 | 2 |
# The data can then be loaded with the rake db:seed (or created alongside the db with db:setup). |
| 3 | 3 |
|
| 4 |
-user = User.find_or_initialize_by(:email => "admin@example.com") |
|
| 5 |
-user.username = "admin" |
|
| 6 |
-user.password = "password" |
|
| 7 |
-user.password_confirmation = "password" |
|
| 4 |
+user = User.find_or_initialize_by(:email => ENV['SEED_EMAIL'] || "admin@example.com") |
|
| 5 |
+user.username = ENV['SEED_USERNAME'] || "admin" |
|
| 6 |
+user.password = ENV['SEED_PASSWORD'] || "password" |
|
| 7 |
+user.password_confirmation = ENV['SEED_PASSWORD'] || "password" |
|
| 8 | 8 |
user.invitation_code = User::INVITATION_CODES.first |
| 9 | 9 |
user.admin = true |
| 10 | 10 |
user.save! |
@@ -0,0 +1,4 @@ |
||
| 1 |
+# This Procfile is intended for Heroku, and is detected by the Gemfile. DO NOT REMOVE THIS LINE! |
|
| 2 |
+ |
|
| 3 |
+# deployment/heroku/unicorn.rb is a special Unicorn config file that also spawns workers. |
|
| 4 |
+web: bundle exec unicorn -p $PORT -c ./deployment/heroku/unicorn.rb |
@@ -0,0 +1,51 @@ |
||
| 1 |
+require "net/http" |
|
| 2 |
+ |
|
| 3 |
+worker_processes Integer(ENV["WEB_CONCURRENCY"] || 2) |
|
| 4 |
+timeout 15 |
|
| 5 |
+preload_app true |
|
| 6 |
+ |
|
| 7 |
+# Note that this will only work correctly when running Heroku with ONE web worker. |
|
| 8 |
+# If you want to run more than one, use the standard Huginn Procfile instead, with separate web and job entries. |
|
| 9 |
+# You'll need to set the Heroku config variable PROCFILE_PATH to 'Procfile'. |
|
| 10 |
+Thread.new do |
|
| 11 |
+ worker_pid = nil |
|
| 12 |
+ while true |
|
| 13 |
+ if worker_pid.nil? |
|
| 14 |
+ worker_pid = spawn("bundle exec rails runner bin/threaded.rb")
|
|
| 15 |
+ puts "New threaded worker PID: #{worker_pid}"
|
|
| 16 |
+ end |
|
| 17 |
+ |
|
| 18 |
+ sleep 45 |
|
| 19 |
+ |
|
| 20 |
+ if ENV['DOMAIN'] |
|
| 21 |
+ force_ssl = ENV['FORCE_SSL'].present? && ENV['FORCE_SSL'] == 'true' |
|
| 22 |
+ Net::HTTP.get_response(URI((force_ssl ? "https://" : "http://") + ENV['DOMAIN'])) |
|
| 23 |
+ end |
|
| 24 |
+ |
|
| 25 |
+ begin |
|
| 26 |
+ Process.getpgid worker_pid |
|
| 27 |
+ rescue Errno::ESRCH |
|
| 28 |
+ # No longer running |
|
| 29 |
+ worker_pid = nil |
|
| 30 |
+ end |
|
| 31 |
+ end |
|
| 32 |
+end |
|
| 33 |
+ |
|
| 34 |
+before_fork do |server, worker| |
|
| 35 |
+ Signal.trap 'TERM' do |
|
| 36 |
+ puts 'Unicorn master intercepting TERM and sending myself QUIT instead' |
|
| 37 |
+ Process.kill 'QUIT', Process.pid |
|
| 38 |
+ end |
|
| 39 |
+ |
|
| 40 |
+ defined?(ActiveRecord::Base) and |
|
| 41 |
+ ActiveRecord::Base.connection.disconnect! |
|
| 42 |
+end |
|
| 43 |
+ |
|
| 44 |
+after_fork do |server, worker| |
|
| 45 |
+ Signal.trap 'TERM' do |
|
| 46 |
+ puts 'Unicorn worker intercepting TERM and doing nothing. Wait for master to send QUIT' |
|
| 47 |
+ end |
|
| 48 |
+ |
|
| 49 |
+ defined?(ActiveRecord::Base) and |
|
| 50 |
+ ActiveRecord::Base.establish_connection |
|
| 51 |
+end |